前一個章節有提到範疇泡泡,
那這些泡泡除了最外圈的全域變數外,
難道建立範疇泡泡只能透過函式嗎?
讓我們繼續看下去~
在 JS 的世界中函式會為自己建立一個範疇泡泡,ES6
以前除了函式外沒有任何結構可以建立他們自己的範疇泡泡。
那函式範疇所造成的影響是什麼?
所有的變數都是屬於函式內部的,
也就是說在全域範疇是無法使用的,如下面的範例。
function foo(){
const a = 123;
function boo(){
const b = 321;
}
const c = 567;
}
foo(); // 可呼叫
console.log(boo()); // 呼叫失敗,拋出 ReferenceError
console.log(a,b,c); // 呼叫失敗,拋出 ReferenceError
使用函式範疇其實就有點像是把你的程式碼包裹起來,而當任何人使用該函式他就會被綁到新的包裹函式的範疇上,而不是之前他的範疇 (真繞口)。
這有什麼好處?
實際來看看
function foo(a){
function boo(a){
return a-1;
}
const b = a + boo(a*5);
console.log(b);
}
foo(2); // 11
他可以將 b
以及 boo()
完全區隔開不受外界影響,讓私有的保持私有。
看起來很正常啊,如果不這麼做會發生什麼事
可以看一下下面的範例
function foo(a){
b = a + boo(a*5);
console.log(b);
}
function boo(a){
return a-1;
}
var b;
foo(2); // 11
等等等等...
結果還是一樣啊!?
那感覺沒差吧?
才怪!
你這樣做的話 b
在全域範疇內,誰都有可能造成你無法預料的後果,萬一被存取加減一下,就會造成你內心原本預期的效果,這就可以應證上面所說的"讓私有的保持私有"的好處。
此外因為變數 b
和函式 boo()
被完全阻隔,也可以避免識別字的重複。
剛剛聽起來滿完美的,
但是其實就算是這樣還可能會造成範疇的污染,
例如以下範例
const a = 2;
function foo(){
const a = 3;
console.log(a);
}
foo(); // 用了 foo 這個識別字
console.log(a); // 2
foo
這個 function 明顯是要執行,
雖然也用隱藏的方式阻隔了 a
變數,
避免私有變數被存取,
但是本身的 foo
卻污染了該範疇,
那該怎麼做才好?
你可以透過 IIFE
(即刻調用的函式運算式)
我怎麼記得我之前文章寫過 xDD
之後回頭再補上連結。
簡單來說他可以將函式透過()
包裹起來,變成一個運算式,並且在最尾段再加上 ()
來執行該函式。
拿上面的例子改一下
const a = 2;
(function foo(){
const a = 3;
console.log(a);
})(); // 3 直接被調用
console.log(a); // 2
foo(); // ReferenceError 噴爆你
這就可以很明白的知道這樣連他本身都不會污染包含他的範疇了。
剛剛在上面提到了 IIFE
書中也提了一些我不知道的事,
我覺得滿有趣的也跟你們分享,
以前的 IIFE
形式某些人會使用以下的方式
(function (){
console.log(17)
}()); // 17
我個人比較常看到和使用的是下面這種方式
(function (){
console.log(17)
})(); // 17
這兩種的功能是一模一樣的,純粹只是個人偏好的風格不同。
你渴望爆炸嗎?
還記得之前提過 undefined
有可能會被當成變數被亂搞,當你使用 IIFE
就可以避免悲劇發生保證 undefined
是你認識的 undefined
undefined = true; // 弄爆你
(function foo(){
let a;
if (a === undefined){
console.log('沒爆炸')
}
})(); // 沒爆炸
他可以透過最後的 ()
傳入參數,
(function (num){
console.log(num)
})(123); // 123
要執行的函式不會先出現,而是在調用和傳入給他參數之後出現,很常被用在 UMD (Universal Module Definition)
專案中。 (完全沒聽過啊!我好菜 Orz)
var a = 2;
( function foo(func) {
func(window);
})( function boo(global) {
const a = 3;
console.log(a); // 3
console.log(global.a); // 2
});
簡單來說他就是透過參數的方式帶入整個 boo
function,再傳入 windows
這全域變數作為 global
參數。
以上是今天的分享
啊... 明天已經是中秋連假的開始,
看來我要抱著筆電去台南玩了 QQ
越來越硬的感覺xDD
還記得開賽的前五天...
再看看現在的我...
然後今天準備要開始寫文章的時候發現,
已經有一批人已經完賽惹 Orz
在此敬佩那些完賽的鐵人們。
好啦~ 明天見~
你所不知道的 JS|範疇與 Closures,this 與物件原型 (You Don't Know JS: this & Object Prototypes))